// +----------------------------------------------------------------------
// | JavaWeb_EleVue_Pro前后端分离旗舰版框架 [ JavaWeb ]
// +----------------------------------------------------------------------
// | 版权所有 2021 上海JavaWeb研发中心
// +----------------------------------------------------------------------
// | 官方网站: http://www.javaweb.vip/
// +----------------------------------------------------------------------
// | 作者: 鲲鹏 <javaweb520@gmail.com>
// +----------------------------------------------------------------------
// | 免责声明:
// | 本软件框架禁止任何单位和个人用于任何违法、侵害他人合法利益等恶意的行为，禁止用于任何违
// | 反我国法律法规的一切平台研发，任何单位和个人使用本软件框架用于产品研发而产生的任何意外
// | 、疏忽、合约毁坏、诽谤、版权或知识产权侵犯及其造成的损失 (包括但不限于直接、间接、附带
// | 或衍生的损失等)，本团队不承担任何法律责任。本软件框架只能用于公司和个人内部的法律所允
// | 许的合法合规的软件产品研发，详细声明内容请阅读《框架免责声明》附件；
// +----------------------------------------------------------------------

package com.javaweb.admin.service.impl;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.javaweb.admin.entity.*;
import com.javaweb.admin.mapper.SpbcDetailMapper;
import com.javaweb.admin.mapper.SpbcInvoiceMapper;
import com.javaweb.admin.query.SpbcCustomerQuery;
import com.javaweb.admin.query.SpbcSummaryQuery;
import com.javaweb.admin.service.ISpbcSubmitLogService;
import com.javaweb.admin.vo.spbc.*;
import com.javaweb.common.config.CommonConfig;
import com.javaweb.common.config.UploadFileConfig;
import com.javaweb.common.common.BaseQuery;
import com.javaweb.common.common.BaseServiceImpl;
import com.javaweb.admin.mapper.SpbcMapper;
import com.javaweb.admin.query.SpbcQuery;
import com.javaweb.admin.service.ISpbcService;
import com.javaweb.common.utils.HttpUtils;
import com.javaweb.common.utils.StringUtils;
import com.javaweb.system.entity.Role;
import com.javaweb.system.mapper.RoleMapper;
import com.javaweb.system.utils.ShiroUtils;
import com.javaweb.common.utils.DateUtils;
import com.javaweb.common.utils.JsonResult;
import org.apache.http.Header;
import org.apache.http.message.BasicHeader;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.*;

/**
  * <p>
  *  服务类实现
  * </p>
  *
  * @author 鲲鹏
  * @since 2023-11-27
  */
@Service
public class SpbcServiceImpl extends BaseServiceImpl<SpbcMapper, Spbc> implements ISpbcService {

    @Autowired
    private SpbcMapper spbcMapper;

    @Autowired
    private SpbcDetailMapper spbcDetailMapper;
    @Autowired
    private SpbcInvoiceMapper spbcInvoiceMapper;
    @Autowired
    private SpbcInvsetServiceImpl spbcInvsetServiceImpl;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private ISpbcSubmitLogService spbcSubmitLogService;
    /**
     * 获取数据列表
     *
     * @param query 查询条件
     * @return
     */
    @Override
    public JsonResult getList(BaseQuery query) {
        SpbcQuery spbcQuery = (SpbcQuery) query;
        List<Role> roleList = roleMapper.getRolesByUserId(ShiroUtils.getUserId());
        boolean roleFlag = true;
        for(Role role : roleList){
            if(role.getId() != 15){
                roleFlag = false;
                break;
            }
        }
        if(roleFlag){
            spbcQuery.setQueryUser(ShiroUtils.getUserId());
        }

        // 获取数据列表
        IPage<Spbc> page = new Page<>(spbcQuery.getPage(), spbcQuery.getLimit());
        IPage<Spbc> pageData = spbcMapper.getSpbcList(page, spbcQuery);
        pageData.convert(x -> {
            SpbcListVo spbcListVo = Convert.convert(SpbcListVo.class, x);
            List<String> yjidList = spbcMapper.getBcyjById(spbcListVo.getId());
            List<String> custaddr = spbcMapper.getCustAddrById(spbcListVo.getId());
            spbcListVo.setCustAddr(custaddr);
            spbcListVo.setBcyjList(yjidList);
            return spbcListVo;
        });
        return JsonResult.success(pageData);
    }

    @Override
    public JsonResult getSpbcCustomerList(BaseQuery query) {
        SpbcCustomerQuery customerQuery = (SpbcCustomerQuery) query;
        if(StringUtils.isEmpty(customerQuery.getCustcode())) {
            customerQuery.setCustcode("1234@0000");
        }
        IPage<SpbcCustomer> page = new Page<>(customerQuery.getPage(), customerQuery.getLimit());
        IPage<SpbcCustomer> pageData = spbcMapper.getSpbcCustomerList(page, customerQuery);
        return JsonResult.success(pageData);

    }

    @Override
    public JsonResult getSpbcSummaryList(BaseQuery query) {
        SpbcSummaryQuery summaryQuery = (SpbcSummaryQuery) query;
        List<SpbcSummary> pageData = spbcMapper.getSpbcSummaryList(summaryQuery);
        return JsonResult.success(pageData);
    }
    @Override
    public JsonResult getSpbcDetailList(SpbcSummaryQuery query) {
        List<SpbcSummary> pageData = spbcMapper.getSpbcDetailList(query);
        return JsonResult.success(pageData);
    }

    @Override
    public JsonResult getSpbcInvoiceList(BaseQuery query) {
        SpbcSummaryQuery summaryQuery = (SpbcSummaryQuery) query;
        List<SpbcSummary> pageData = spbcMapper.getSpbcInvoiceList(summaryQuery);
        return JsonResult.success(pageData);
    }

    @Override
    public JsonResult getSpbcDetail(SpbcSummaryQuery query) {
        List<SpbcSummary> pageData = spbcMapper.getSpbcDetail(query);
        return JsonResult.success(pageData);
    }

    @Override
    public JsonResult getSpbcInvoiceDetail(BaseQuery query) {
        SpbcSummaryQuery summaryQuery = (SpbcSummaryQuery) query;
        List<SpbcSummary> pageData = spbcMapper.getSpbcInvoiceDetail(summaryQuery);
        return JsonResult.success(pageData);
    }

    @Override
    public JsonResult updateCheckFlag(Integer id,String flag) {
        UpdateWrapper<Spbc> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("check_flag", flag).set("submit_time", DateUtils.now()).eq("id", id);

        //推送简道云
        if(flag.equals("Y")) {
            SpbcInfoVo spbcInfoVo = (SpbcInfoVo) getInfo(id);
            String postUrl = CommonConfig.fdlBcUrl + "&spbc=" + spbcInfoVo.getSqdh();
            JSONObject ob = new JSONObject();
            ob.put("workId", CommonConfig.bcWorkId);
            JSONObject params = new JSONObject();
            params.put("spbc", spbcInfoVo.getSqdh());
            ob.put("params", params);
            String response = HttpUtils.sendPost2(postUrl, ob.toJSONString());

            SpbcSubmitLog spbcSubmitLog = new SpbcSubmitLog();
            spbcSubmitLog.setSubmitNo(spbcInfoVo.getSqdh());
            spbcSubmitLog.setRequestBody(ob.toJSONString());
            spbcSubmitLog.setSubmitTime(DateUtils.now());
            spbcSubmitLog.setResponseBody(response);
            spbcSubmitLog.setMark(1);

            FDLResult result = JSONObject.parseObject(response, FDLResult.class);
            spbcSubmitLog.setResponseCode(String.valueOf(result.getStatus()));
            spbcSubmitLog.setSubmitUser(ShiroUtils.getUserNo());
            spbcSubmitLogService.save(spbcSubmitLog);

            //轮询fdl任务执行情况
            int attempt = 0;
            boolean uploadStatus = false;
            try {
                Thread.sleep(5000);
            }catch(InterruptedException ex){
            }
            while(attempt<5) {
                String fdlRecordStatusUrl = CommonConfig.fdlRecordStatusUrl + result.getData().getRecordId();
                String resultString = HttpUtils.sendGet(fdlRecordStatusUrl, "");
                String recordStatus = JSONObject.parseObject(resultString).getJSONObject("data").getString("status");

                SpbcSubmitLog spbcSubmitLog2 = new SpbcSubmitLog();
                spbcSubmitLog2.setSubmitNo(spbcInfoVo.getSqdh());
                spbcSubmitLog2.setRequestBody(fdlRecordStatusUrl);
                spbcSubmitLog2.setSubmitTime(DateUtils.now());
                spbcSubmitLog2.setResponseBody(resultString);
                spbcSubmitLog2.setMark(1);
                spbcSubmitLogService.save(spbcSubmitLog2);

                if(recordStatus.equals("SUCCESS")){
                    //附件上传
                    try {
                        jdyUploadFile(spbcInfoVo);
                        uploadStatus = true;
                        log.trace("补差申请单号："+spbcInfoVo.getSqdh()+"附件上传简道云成功。");
                    }catch (Exception ex){
                        log.error("补差申请单号："+spbcInfoVo.getSqdh()+"附件上传简道云失败。");
                        return JsonResult.error("提交失败，请稍后再试或联系管理员");
                    }
                    break;
                }else if(recordStatus.equals("RUNNING") || recordStatus.equals("QUEUING")){
                    attempt++;
                    try {
                        Thread.sleep(3000);
                    }catch(InterruptedException ex){
                    }
                }else{
                    return JsonResult.error("提交失败，请稍后再试或联系管理员");
                }
            }
            if(!uploadStatus){
                return JsonResult.error("提交失败，请稍后再试或联系管理员");
            }

        }
        spbcMapper.update(new Spbc(), updateWrapper);
        return JsonResult.success();
    }

    //简道云附件上传
    public String jdyUploadFile(SpbcInfoVo spbcInfoVo) throws Exception {
        List<Header> headerList = new ArrayList<>();
        headerList.add(new BasicHeader("Authorization", "Bearer " + CommonConfig.jdyApiKey));
        headerList.add(new BasicHeader("Content-Type", "application/json;charset=utf-8"));
        Header[] headers = headerList.toArray(new Header[headerList.size()]);

        //1.获取表单数据
        SpbcSubmitLog spbcSubmitLog1 = new SpbcSubmitLog();
        spbcSubmitLog1.setSubmitNo(spbcInfoVo.getSqdh());
        String uploadUrl1 = CommonConfig.jdyFileUploadUrl1;
        JSONObject ob1 = new JSONObject();
        ob1.put("app_id", CommonConfig.jdyAppId);
        ob1.put("entry_id", CommonConfig.jdyEntryId);
        JSONArray fieldsArray = new JSONArray();
        fieldsArray.add("sqdh");
        ob1.put("fields", fieldsArray);
        JSONObject cond = new JSONObject();
        JSONArray condArray = new JSONArray();
        cond.put("field", "sqdh");
        cond.put("type", "String");
        cond.put("method", "eq");
        cond.put("value", spbcInfoVo.getSqdh());
        condArray.add(cond);
        JSONObject filter = new JSONObject();
        filter.put("rel", "and");
        filter.put("cond", condArray);
        ob1.put("filter", filter);
        Map<String, Object> result1 = HttpUtils.sendSSLPost2(uploadUrl1, headers, ob1.toJSONString());
        spbcSubmitLog1.setRequestBody(ob1.toJSONString());
        spbcSubmitLog1.setSubmitTime(DateUtils.now());
        spbcSubmitLog1.setResponseBody(result1.toString());
        spbcSubmitLog1.setMark(1);
        spbcSubmitLogService.save(spbcSubmitLog1);

        LinkedHashMap data = (LinkedHashMap)((ArrayList)result1.get("data")).get(0);
        String transactionId = data.get("_id").toString();



        //2.获取文件上传凭证
        SpbcSubmitLog spbcSubmitLog2 = new SpbcSubmitLog();
        spbcSubmitLog2.setSubmitNo(spbcInfoVo.getSqdh());
        String uploadUrl2 = CommonConfig.jdyFileUploadUrl2;
        JSONObject ob2 = new JSONObject();
        ob2.put("app_id", CommonConfig.jdyAppId);
        ob2.put("entry_id", CommonConfig.jdyEntryId);
        ob2.put("transaction_id", transactionId);
        Map<String, Object> result2 = HttpUtils.sendSSLPost2(uploadUrl2, headers,ob2.toJSONString());
        spbcSubmitLog2.setRequestBody(ob2.toJSONString());
        spbcSubmitLog2.setSubmitTime(DateUtils.now());
        spbcSubmitLog2.setResponseBody(result2.toString());
        spbcSubmitLog2.setMark(1);
        spbcSubmitLogService.save(spbcSubmitLog2);

        LinkedHashMap tokenAndUrl = (LinkedHashMap)((ArrayList)result2.get("token_and_url_list")).get(0);
        String token = tokenAndUrl.get("token").toString();
        String url = tokenAndUrl.get("url").toString();



        //3.上传文件
        SpbcSubmitLog spbcSubmitLog3 = new SpbcSubmitLog();
        spbcSubmitLog3.setSubmitNo(spbcInfoVo.getSqdh());
        String boundary = System.currentTimeMillis() + UUID.randomUUID().toString();
        List<Header> headerList2 = new ArrayList<>();
        headerList2.add(new BasicHeader("Authorization", "Bearer " + "cQURml9nhwu96qkMGWBwTiyYLKQQkqTb"));
        headerList2.add(new BasicHeader("Content-Type", "multipart/form-data;charset=utf-8;boundary="+boundary));
        Header[] headers2 = headerList2.toArray(new Header[headerList2.size()]);
        String filePath = UploadFileConfig.uploadFolder.replace('\\','/')+spbcInfoVo.getUploadfile();
        Map<String, String> ob3 = new HashMap<>();
        ob3.put("token", token);
        Map<String, Object> result3 = HttpUtils.sendSSLPostFile(url, headers2, ob3, filePath, boundary);
        spbcSubmitLog3.setRequestBody(ob3.toString());
        spbcSubmitLog3.setSubmitTime(DateUtils.now());
        spbcSubmitLog3.setResponseBody(result3.toString());
        spbcSubmitLog3.setMark(1);
        spbcSubmitLogService.save(spbcSubmitLog2);

        String key = result3.get("key").toString();

        //4.修改表单
        SpbcSubmitLog spbcSubmitLog4 = new SpbcSubmitLog();
        spbcSubmitLog4.setSubmitNo(spbcInfoVo.getSqdh());
        String uploadUrl4 = CommonConfig.jdyFileUploadUrl4;
        JSONObject ob4 = new JSONObject();
        ob4.put("app_id", CommonConfig.jdyAppId);
        ob4.put("entry_id", CommonConfig.jdyEntryId);
        ob4.put("transaction_id", transactionId);
        ob4.put("data_id",transactionId);
        JSONObject value = new JSONObject();
        JSONArray array = new JSONArray();
        array.add(key);
        value.put("value",array);
        JSONObject dd = new JSONObject();
        dd.put("fj",value);
        ob4.put("data",dd);
        ob4.put("is_start_trigger",true);
        Map<String, Object> result4 = HttpUtils.sendSSLPost2(uploadUrl4, headers, ob4.toJSONString());
        spbcSubmitLog4.setRequestBody(ob4.toJSONString());
        spbcSubmitLog4.setSubmitTime(DateUtils.now());
        spbcSubmitLog4.setResponseBody(result4.toString());
        spbcSubmitLog4.setMark(1);
        spbcSubmitLogService.save(spbcSubmitLog4);
        return result4.toString();
    }

    @Override
    public JsonResult uploadFile(MultipartFile file) {
        String dateStr = DateUtils.dateTimeNow();
        String fileName = dateStr + '_' + file.getOriginalFilename();
        if(file.getSize()>1024*1024*10){
            return JsonResult.error("上传文件大小不能超过10M");
        }
        File filePath = new File("");
        //当前项目下路径+静态资源实际存储路径
        String path=filePath.getAbsolutePath();
        String templatePath = UploadFileConfig.uploadFolder;

        templatePath=templatePath.replace('\\','/');
        File dests = new File(templatePath);
        File dest = new File(dests, fileName);
        //文件上传-覆盖
        try {
            // 检测是否存在目录
            if(!dests.exists()){
                dests.mkdirs();
            }
            // getParentFile获取上一级
            if (!dest.getParentFile().exists()) {
                dest.getParentFile().mkdirs();
            }
            file.transferTo(dest);

            return JsonResult.success(fileName);//上传成功,文件名以逗号隔开
        } catch (Exception e) {
            return JsonResult.error("上传失败，失败原因："+e.getMessage());
        }
    }

    @Override
    public JsonResult saveSpbc(SpbcDto entity) {
        Spbc spbc = entity.getHeadInfo();
        SpbcSummary[] summaries = entity.getSpbcSummaries();
        Map<String, SpbcInvoice[]> invoices = entity.getSpbcInvoices();
        SpbcDetail spbcDetail = new SpbcDetail();
        Map<String, String> didMap = new HashMap<>();
        try {
            if(StringUtils.isNotNull(spbc.getId()) && spbc.getId() > 0) {
                spbc.setUpdateUser(ShiroUtils.getUserId());
                spbc.setUpdateTime(DateUtils.now());
                spbcMapper.updateById(spbc);
                spbcMapper.deleteYjById(spbc.getId());
                spbcMapper.deleteCustAddrById(spbc.getId());
            }else {
                String newSqdh = spbcMapper.getNewSqdh("BC" + DateUtils.getDate2()+"000");
                if(StringUtils.isNotNull(newSqdh)) {
                    newSqdh = "BC" + String.valueOf(Long.parseLong(newSqdh) + 1);
                }else{
                    newSqdh =  "BC" + DateUtils.getDate2()+"001";
                }
                spbc.setSqr(ShiroUtils.getUserInfo().getRealname());
                spbc.setSqdh(newSqdh);
                spbc.setSqrq(DateUtils.getDate());
                spbc.setCreateUser(ShiroUtils.getUserId());
                spbc.setCreateTime(DateUtils.now());
                spbcMapper.insert(spbc);
            }
            for(String yj : spbc.getBcyjList()){
                spbcMapper.insertBcyj(spbc.getId(), yj);
            }
            if(spbc.getCustAddr() != null) {
                for (String addr : spbc.getCustAddr()) {
                    spbcMapper.insertCustAddr(spbc.getId(), addr);
                }
            }
            List<Integer> oriDetailIds = spbcMapper.getSpbcDetailIdList(spbc.getId());
            List<Integer> newDetailIds = new ArrayList<>();
            for (SpbcSummary summary:summaries) {
                SpbcDetail detail = new SpbcDetail();
                String tempDid = "";
                if (StringUtils.isNotNull(summary.getId()) && summary.getId().length() > 18) {
                    tempDid = summary.getId();
                    summary.setId("");
                }else{
                    detail.setId(Integer.parseInt(summary.getId()));
                    newDetailIds.add(Integer.parseInt(summary.getId()));
                }
                BeanUtils.copyProperties(summary, detail);

                detail.setPid(spbc.getId());

                if (StringUtils.isNotNull(detail.getId()) && detail.getId() > 0) {
                    detail.setUpdateUser(ShiroUtils.getUserId());
                    detail.setUpdateTime(DateUtils.now());
                    spbcDetailMapper.updateById(detail);
                } else {
                    detail.setCreateUser(ShiroUtils.getUserId());
                    detail.setCreateTime(DateUtils.now());
                    spbcDetailMapper.insert(detail);
                    didMap.put(tempDid, String.valueOf(detail.getId()));
                }
            }

            for(Integer id : oriDetailIds){
                if(!newDetailIds.contains(id)){
                    spbcMapper.deleteSpbcDetailById(id,ShiroUtils.getUserId());
                    spbcMapper.deleteSpbcInvoiceByDid(id,ShiroUtils.getUserId());
                }
            }
            for(String key : invoices.keySet()) {
                for(SpbcInvoice invoice : invoices.get(key)) {
                    if(StringUtils.isNotNull(invoice.getId()) && invoice.getId() > 0) {
                        invoice.setUpdateUser(ShiroUtils.getUserId());
                        invoice.setUpdateTime(DateUtils.now());
                        if (BigDecimal.ZERO.compareTo(invoice.getQuantity()) < 0) {
                            spbcInvoiceMapper.updateById(invoice);
                        }else{
                            spbcInvoiceMapper.deleteById(invoice.getId());
                        }
                    }
                    else {
                        invoice.setPid(spbc.getId());
                        if(didMap.containsKey(key)) {
                            invoice.setDid(didMap.get(key));
                        }else{
                            invoice.setDid(key);
                        }
                        invoice.setCreateUser(ShiroUtils.getUserId());
                        invoice.setCreateTime(DateUtils.now());
                        if (BigDecimal.ZERO.compareTo(invoice.getQuantity()) < 0) {
                            spbcInvoiceMapper.insert(invoice);
                        }
                    }
                }

            }

            return JsonResult.success();
        }
        catch(Exception ex)
        {
            return JsonResult.error(ex.getMessage());
        }
    }

    /**
     * 获取详情Vo
     *
     * @param id 记录ID
     * @return
     */
    @Override
    public Object getInfo(Serializable id) {
        Spbc entity = (Spbc) super.getInfo(id);
        // 返回视图Vo
        SpbcInfoVo spbcInfoVo = new SpbcInfoVo();
        // 拷贝属性
        BeanUtils.copyProperties(entity, spbcInfoVo);
        return spbcInfoVo;
    }

    /**
     * 添加、更新记录
     *
     * @param entity 实体对象
     * @return
     */
    @Override
    public JsonResult edit(Spbc entity) {
        if (StringUtils.isNotNull(entity.getId()) && entity.getId() > 0) {
        } else {
        }
        return super.edit(entity);
    }

    /**
     * 删除记录
     *
     * @param entity 实体对象
     * @return
     */
    @Override
    public JsonResult delete(Spbc entity) {
        entity.setMark(0);
        return super.delete(entity);
    }

    @Override
    public JsonResult deleteById(Integer id) {
        try {
            spbcMapper.deleteById(id, ShiroUtils.getUserId());
            return JsonResult.success();
        }
        catch(Exception ex)
        {
            return JsonResult.error(ex.getMessage());
        }
    }

    @Override
    public void deleteSpbcDetailByPid(Integer pid) {
        spbcMapper.deleteSpbcDetailByPid(pid,ShiroUtils.getUserId());
    }

    @Override
    public void deleteSpbcInvoiceByPid(Integer pid) {
        spbcMapper.deleteSpbcInvoiceByPid(pid,ShiroUtils.getUserId());
    }

    @Override
    public JsonResult getCustAddrList(String custcode) {
        List<SpbcCustAddr> custAddrList = spbcMapper.getCustAddrList(custcode);
        return JsonResult.success(custAddrList);
    }

}